using System;
using Real = System.Double;

namespace LinearAlgebra.Vectors.Numeric
{
	/// <summary>
	/// A vector whose components are elements of the real number domain
	/// </summary>
	public partial class RealVector : Vector<Real>
	{
		/// <summary>
		/// Creates an Empty Vector
		/// </summary>
		public RealVector() {}

		/// <summary>
		/// Initialize a vector of real numbers
		/// </summary>
		/// <param name="n">the number of Real Numbers that the vector can hold</param>
		public RealVector( int n ) : base( n ) {			
			for( int i = 0; i < n; i++ )	
				this.Add( 0 ); //otherwise the indexer will fail
		}
	
		/// <summary>
		/// Create a vector by using this syntax new RealVector( 1, 2, 3, 4, ... )
		/// </summary>		
		public RealVector( params Real[] entries )
		{
			foreach( Real d in entries )
				this.Add( d );
		}		

		public bool Equals( RealVector u, Real maxDiff )
		{
			AssertSize( this, u );
			for( int i = 0; i < this.Length; i++ )			
				if( Math.Abs( this[i] - u[i] ) > maxDiff )
					return false;			
			return true;
		}

		/// <summary>
		/// Elementwise addition of the vector elements u+v = (u1+v1, u2+v2, u3+v3)
		/// </summary>
		public static RealVector operator+( RealVector u, RealVector v )
		{
			AssertSize( u, v );
			RealVector result = new RealVector( u.Count );
			for (int i = 0; i < u.Count; i++ )
				result[i] = u[i] + v[i];			
			return result;
		}
		/// <summary>
		/// Adds a given scalar to every element of the vector
		/// </summary>		
		public static RealVector operator+( RealVector u, Real scalar )
		{
			RealVector result = new RealVector( u.Count );
			for (int i = 0; i < u.Count; i++ )
				result[i] = u[i] + scalar;
			return result;
		}		
		/// <summary>
		/// Adds a given scalar to every element of the vector
		/// </summary>		
		public static RealVector operator+( Real scalar, RealVector u )
		{
			return u + scalar;
		}

		/// <summary>
		/// Negation operator on the vector's values
		/// </summary>		
		public static RealVector operator-( RealVector u )
		{
			RealVector result = new RealVector();			
			u.ForEach( x => result.Add( -x ) );
			return result;
		}
		/// <summary>
		/// Implements element by element subtraction
		/// </summary>		
		public static RealVector operator-( RealVector u, RealVector v )
		{
			AssertSize( u, v );			
			return u + (-v);
		}
		/// <summary>
		/// Subtracts from each element of the vector the given value
		/// </summary>
		/// <param name="u">The vector</param>
		/// <param name="scalar">The value to subtract from each element</param>		
		public static RealVector operator-( RealVector u, Real scalar )
		{
			return u + (-scalar);			
		}
		/// <summary>
		/// Subtracts from each element of the vector the given value
		/// </summary>
		/// <param name="u">The vector</param>
		/// <param name="scalar">The value to subtract from each element</param>		
		public static RealVector operator-( Real scalar, RealVector u )
		{
			RealVector result = new RealVector( u.Count );
			for( int i = 0; i < u.Count; i++ )
				result[i] = scalar - u[i]; //TODO: is there a way to eliminate this
			return result;
		}

		/// <summary>
		/// Scalar Multiplication
		/// </summary>		
		public static RealVector operator*( RealVector u, Real scalar )
		{
			RealVector result = new RealVector( u.Count );
			for( int i = 0; i < u.Count; i++ )
				result[i] = u[i] * scalar;
			return result;
		}

		/// <summary>
		/// Scalar Multiplication
		/// </summary>		
		public static RealVector operator*( Real scalar, RealVector u ) {
			return u * scalar; //order doesn't matter on this
		}
        
		/// <summary>
		/// Performs dot product multiplication on two vectors yielding a single value
		/// </summary>		
		public static Real operator*( RealVector u, RealVector v )
		{
			return u.Dot( v );
		}

		/// <summary>
		/// Returns the dot product of the current vector with the supplied one
		/// </summary>		
		public Real Dot( RealVector v )
		{
			RealVector u = this;
			AssertSize( u, v );
			Double sum = 0;
			for( int i = 0; i < u.Count; i++ )
				sum += u[i]*v[i];
			return sum;
		}		

		/// <summary>
		/// Returns the maximum value in a vector
		/// </summary>		
		public Real Max()
		{
			Double max = this[0];
			foreach (Double el in this)
				if( el > max )					
					max = el; //otherwise							
			return max;
		}
	}
}